/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - graphics/shaders
// Copyright( c) 2014.  All Rights Reserved
//
// File:		AEShaderConstantTable.h
// Author:		Gianluca Belardelli
// Date:		29/01/2015
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESHADERCONSTANTTABLE_H_
#define _AESHADERCONSTANTTABLE_H_

#if defined(AE_OPENGL)
#define AECONSTANTBUFFER_REGISTER_SIZE	16
#else
#define AECONSTANTBUFFER_REGISTER_SIZE	1
#endif

class AEShaderConstantTable : public AEReferencedObject
{
// Members
private:
	AEINT32						m_nEntryCount;
	AEINT32						m_nFirstRegister;
	
	AEShaderConstantTableEntry	*m_lpEntry;

	AEFLOAT32					*m_lpBuffer;
// Methods
private:
	AEShaderConstantTable( const AEShaderConstantTable & );
	//void operator = (const AEShaderConstantTable & );

public:

	/// \brief
	///   Constructor
	AE_FORCEINLINE AEShaderConstantTable( void );

	/// \brief
	///   Destructor
	AE_FORCEINLINE ~AEShaderConstantTable( void );

	/// \brief
	///   Resets the table
	AE_FORCEINLINE void Reset( void );

	AE_DLLIMPEXP AEBOOL32 AddEntry( AEINT32 nReg, AEShaderConstantTableEntry *lpEntry );

	/// \brief
	///   Reserves memory for nCount table entries
	AE_DLLIMPEXP void AllocateEntries( AEINT32 nCount );

	/// \brief
	///   Helper function to evaluate the min/max register indices over all table entries
	AE_DLLIMPEXP void GetRegisterRange( AEINT32 &nFirst, AEINT32 &nLast ) const;

	/// \brief
	///   Returns the maximum index of a texture sampler (or -1 if no samplers are used)
	AE_DLLIMPEXP AEINT32 GetMaxSamplerIndex( void ) const;

	/// \brief
	///   Returns the table entry (or NULL) that is a texture sampler and maps to the specified
	///   sampler index
	AE_DLLIMPEXP AEShaderConstantTableEntry *FindSamplerWithIndex( AEINT32 nSampler ) const;

	/// \brief
	///   Looks up a table entry by variable name
	/// 
	/// The string comparison is case-insensitive.
	/// 
	/// \param szVarName
	///   Variable name to find in this table.
	/// 
	/// \return
	///   VShaderConstantTableEntry* pEntry: The table entry, if found. Otherwise NULL.
	AE_DLLIMPEXP AEShaderConstantTableEntry *FindByName( const char *lpVarName ) const;

	/// \brief
	///   Finds a sampler entry type by name and returns the sampler index (or -1).
	AE_DLLIMPEXP AEINT32 GetSamplerIndexByName( const char *lpSamplerName ) const;

	/// \brief
	///   Finds a shader constant table entry that uses the passed start register.
	AE_DLLIMPEXP AEShaderConstantTableEntry *FindByStartRegister( AEINT32 nStartReg ) const;

	/// \brief
	///   Returns the number of entries in the shader constant table
	AE_DLLIMPEXP AEINT32 GetNumEntries (void) const;

	/// \brief
	///   Returns the entry at a given index in the shader constant table
	AE_DLLIMPEXP const AEShaderConstantTableEntry *GetEntry( AEINT32 nEntry ) const;

	/// \brief
	///   Returns the entry at a given index in the shader constant table
	AE_DLLIMPEXP AEShaderConstantTableEntry *GetEntry( AEINT32 nEntry);

	/// @name Modifying Values
	/// @{
	///
	AE_DLLIMPEXP void *Lock( AEINT32 nFirstEntry, AEINT32 nEntryCount, AEINT32 nLockFlags );
	AE_DLLIMPEXP void Unlock( void );

	/// \brief
	///   Helper function to lock a register range using the variable's name
	/// 
	/// This function uses the associated constant table to look up the variable's register range.
	/// 
	/// Since this function involves string comparisons, it should not be used frequently at
	/// runtime. Instead, register indices should be evaluated at compile time using
	/// GetRegisterByName, stored as custom shader members and passed to the Lock function or
	/// variants of SetSingleRegister
	/// 
	/// \param szVarname
	///   The variable's name as used in the shader source code (string match is case-insensitive)
	/// 
	/// \param iLockFlags
	///   Lock flags; see Lock operation for supported flag constants
	/// 
	/// \param pRegCount
	///   Optional int reference that will receive the number of 4-component registers used by this
	///   variable. The value is the same as VShaderConstantTableEntry::GetRegisterCount for the
	///   resp. variable.
	/// 
	/// \return
	///   float *pFirstReg : system memory address of the first register (or NULL if variable does
	///   not exist)
	/// 
	/// \sa IVConstantBuffer::Lock
	AE_FORCEINLINE void *LockByName( const char *lpVarname, AEINT32 nLockFlags, AEINT32 *lpRegCount = AENULL );

	/// \brief
	///   Helper function to modify a single variable
	/// 
	/// This function wraps around LockByName and fills the buffer with the parsing result of the
	/// value string.
	/// 
	/// See performance hints there.
	/// 
	/// \param szVarName
	///   The variable to modify
	/// 
	/// \param szValueStr
	///   The value string to parse and write into the locked buffer. Vector portions have to be
	///   separated by comma, e.g. "0,100,200". If there are not enough parameters in the string
	///   (e.g. passing "0,100,200" for a VALUETYPE_FLOAT4 variable type) the remaining portions are
	///   not modified (rather than setting to 0.0). If there are too many portions in the value
	///   string the last ones are ignored.
	/// 
	/// \return
	///   bool bResult: true, if the operation was successful (e.g. the variable has to exist)
	/// 
	/// \sa IVConstantBuffer::LockByName
	/// \sa IVConstantBuffer::SetSingleRegisterF
	AE_DLLIMPEXP AEBOOL32 SetSingleParameter( const char *lpVarName, const char *lpValueStr);

	/// \brief
	///   Helper function to modify a single variable.
	/// 
	/// This function wraps around LockByName and copies the source buffer into the lock target.
	/// 
	/// See performance hints there.
	/// 
	/// \param szVarName
	///   The variable to modify
	/// 
	/// \param pValues
	///   The source buffer. This buffer has to point to a float array that is large enough to copy
	///   at least 4 floats. The actual number of floats copied depends on the iMaxRegister parameter
	///   resp. the register range used by this variable. However, it is always a multiple of 4
	///   floats.
	/// 
	/// \param iMaxRegister
	///   If specified, at most iMaxRegister*4 floats are copied. Otherwise, the number of floats is
	///   evaluated from the variable type and array size.
	/// 
	/// \return
	///   bool bResult: true, if the operation was successful (e.g. the variable has to exist)
	/// 
	/// \sa IVConstantBuffer::LockByName
	/// \sa IVConstantBuffer::SetSingleRegisterF
	AE_DLLIMPEXP AEBOOL32 SetSingleParameterF( const char *lpVarName, const AEFLOAT32 *lpfValues, AEINT32 nMaxRegister = -1 );

	/// \brief
	///   Helper function to modify a single variable
	/// 
	/// This function wraps around LockByName and copies the passed float scalars into the first
	/// register.
	/// 
	/// Thus this version is suitable for single float types or float vectors, but not for matrices
	/// or arrays.
	/// 
	/// See performance hints in LockByName.
	/// 
	/// \param szVarName
	///   The variable to modify
	/// 
	/// \param x,y,z,w
	///   4 float scalars that are written into the first register.
	/// 
	/// \return
	///   bool bResult: true, if the operation was successful (e.g. the variable has to exist)
	/// 
	/// \sa IVConstantBuffer::LockByName
	/// \sa IVConstantBuffer::SetSingleRegisterF
	AE_DLLIMPEXP AEBOOL32 SetSingleParameterF( const char *lpVarName, AEFLOAT32 fX, AEFLOAT32 fY, AEFLOAT32 fZ, AEFLOAT32 fW );


	/// \brief
	///   Returns the number of bytes used by this buffer
	AE_FORCEINLINE AEINT32 GetByteCount( void ) const;

	///
	/// @name Operators
	/// @{

	/// \brief
	///   Assignment operator. Deep copies the buffer.
	AE_FORCEINLINE AEShaderConstantTable &operator = ( const AEShaderConstantTable &other );

	/// \brief
	///   Comparison operator. true if both buffers contain the exact same data
	AE_FORCEINLINE AEBOOL32 operator == ( const AEShaderConstantTable &other ) const;

	/// \brief
	///   Comparison operator.
	AE_FORCEINLINE AEBOOL32 operator != ( const AEShaderConstantTable &other ) const;
};

#include "AEShaderConstantTable.inl"

#endif // _AESHADERCONSTANTTABLE_H_
